/**
 * 
 */
package org.stayfool.auth.common.util;

import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.sql.Clob;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 
 * @author jiangych
 *
 */
public final class StringUtil {
	private static class InstanceHolder {
		static StringUtil instance = new StringUtil();
	}

	public static StringUtil getInstance() {
		return InstanceHolder.instance;
	}

	private static NumberFormat numberFormatter = NumberFormat.getNumberInstance();

	private static final String DEFAULT_SPLIT_SYBMBOL = ",";
	/**
	 * ASCII表中可见字符从!开始，偏移位值为33(Decimal)
	 */
	static final char DBC_CHAR_START = 33; // 半角!

	/**
	 * ASCII表中可见字符到~结束，偏移位值为126(Decimal)
	 */
	static final char DBC_CHAR_END = 126; // 半角~

	/**
	 * 全角对应于ASCII表的可见字符从！开始，偏移值为65281
	 */
	static final char SBC_CHAR_START = 65281; // 全角！

	/**
	 * 全角对应于ASCII表的可见字符到～结束，偏移值为65374
	 */
	static final char SBC_CHAR_END = 65374; // 全角～
	/**
	 * ASCII表中除空格外的可见字符与对应的全角字符的相对偏移
	 */
	static final int CONVERT_STEP = 65248; // 全角半角转换间隔
	/**
	 * 全角空格的值，它没有遵从与ASCII的相对偏移，必须单独处理
	 */
	static final char SBC_SPACE = 12288; // 全角空格 12288

	/**
	 * 半角空格的值，在ASCII中为32(Decimal)
	 */
	static final char DBC_SPACE = ' '; // 半角空格

	public static String append(String string1, String string2) {
		StringBuffer stringBuffer = new StringBuffer();
		stringBuffer.append(string1);
		return string1 + string2;
	}

	/**
	 * <PRE>
	 * 半角字符->全角字符转换 
	 * 只处理空格，!到˜之间的字符，忽略其他
	 * </PRE>
	 */
	public static String bj2qj(String src) {
		if (src == null) {
			return src;
		}
		StringBuilder buf = new StringBuilder(src.length());
		char[] ca = src.toCharArray();
		for (int i = 0; i < ca.length; i++) {
			if (ca[i] == DBC_SPACE) { // 如果是半角空格，直接用全角空格替代
				buf.append(SBC_SPACE);
			} else if ((ca[i] >= DBC_CHAR_START) && (ca[i] <= DBC_CHAR_END)) { // 字符是!到~之间的可见字符
				buf.append((char) (ca[i] + CONVERT_STEP));
			} else { // 不对空格以及ascii表中其他可见字符之外的字符做任何处理
				buf.append(ca[i]);
			}
		}
		return buf.toString();
	}

	public static String bytesToString(byte[] bytes) {

		return bytesToString(bytes, "UTF-8");

	}

	public static String bytesToString(byte[] bytes, String charset) {
		try {
			return new String(bytes, charset);
		} catch (UnsupportedEncodingException e) {
			return null;
		}
	}

	public static boolean canParseToInt(String inputValue) {
		try {
			Integer.parseInt(inputValue);
			return true;
		} catch (java.lang.NumberFormatException ex) {
		}
		return false;
	}

	public static String changeLength(String string, int length) {
		if (string.length() > length)
			string = string.substring(0, length);
		while (string.length() < length)
			string += " ";
		return string;
	}

	public static String changeLengthLeft(String string, int length, String strInsert) {
		if (string.length() > length)
			return string;
		while (string.length() < length)
			string = strInsert + string;
		return string;
	}

	/**
	 * 是否存在\n
	 * 
	 * @param text
	 * @return
	 */
	public static boolean containsLF(String text) {
		if (isNullOrEmpty(text))
			return false;
		Pattern crlf = Pattern.compile("\n");
		Matcher matcher = crlf.matcher(text);
		return matcher.find();
	}

	public static List<String[]> convertObjectArrayToStringArray(List<Object[]> objectArrayList) {

		List<String[]> strArryList = new ArrayList<String[]>(objectArrayList.size());
		for (Object[] objArray : objectArrayList) {
			int len = Array.getLength(objArray);
			String[] strArry = new String[len];
			for (int i = 0; i < len; i++) {
				strArry[i] = objArray[i].toString();
			}
			strArryList.add(strArry);
		}
		return strArryList;
	}

	/**
	 * 矫正\n|\r|\n\r为\r\n
	 * 
	 * @param text
	 * @return
	 */
	public static String correctCRLF(String text) {
		if (isNullOrEmpty(text))
			return text;
		Pattern crlf = Pattern.compile("\n");
		Matcher matcher = crlf.matcher(text);

		if (matcher.find()) {
			String newText = matcher.replaceAll("\r\n");
			crlf = Pattern.compile("\r\r");
			matcher = crlf.matcher(newText);
			if (matcher.find()) {
				newText = matcher.replaceAll("\r");
			}
			return newText;
		} else
			return text;
	}

	/**
	 * 统计\n出现次数
	 * 
	 * @param text
	 * @return
	 */
	public static int countLF(String text) {
		if (isNullOrEmpty(text))
			return 0;
		Pattern crlf = Pattern.compile("\n");
		Matcher matcher = crlf.matcher(text);
		int count = 0;
		while (matcher.find()) {
			count++;
		}
		return count;
	}

	public static String dateLongStringFromDate(Date date) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
		String dateStr = sdf.format(date);
		return dateStr;
	}

	/**
	 * @param date
	 *            means the origin of the date string
	 * @return the String with ****-**-** style
	 */
	public static String dateShortStringFromDate(Date date) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		String dateStr = sdf.format(date);
		dateStr = dateStr.substring(0, 10);
		return dateStr;
	}

	/**
	 * @param date
	 *            means the origin of the date string
	 * @return the String with ****-**-** style
	 */
	public static String dateStringFromDate(Date date) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		String dateStr = sdf.format(date);
		dateStr = dateStr.substring(0, 10);
		return dateStr;
	}

	/**
	 * Find in a string the first none white space character's position.
	 * 
	 * @param line
	 *            The string.
	 * @return The index of the first none white space character.
	 */
	public static int firstNoneSpaceChar(String line) {
		int position = -1;
		for (int i = 0; i < line.length(); i++) {
			if (line.charAt(i) != ' ') {
				position = i;
				break;
			}
		}
		return position;
	}

	/**
	 * 补足长度， 中文占2个字符,英文数字占1个字符
	 * 
	 * @param value
	 * @param len
	 * @return
	 */
	public static final String fixLength(String string, int len) {
		int stringLen = length(string);
		if (stringLen > len)
			return string;

		int fixLen = len - stringLen;
		StringBuffer sb = new StringBuffer();
		while (fixLen-- > 0) {
			sb.append(" ");
		}

		string += sb.toString();
		return string;
	}

	/**
	 * @param number
	 * @param numberDigit
	 * @return
	 * @author kaiyin
	 */
	public static String formatNumber(long number, int numberDigit) {
		numberFormatter.setMaximumIntegerDigits(numberDigit);
		numberFormatter.setMinimumIntegerDigits(numberDigit);
		numberFormatter.setGroupingUsed(false);
		numberFormatter.setMaximumFractionDigits(0);
		return numberFormatter.format(number);
	}

	public static String formatNumber(Object number, String dataFormat) {
		if (number == null)
			return "";

		if (StringUtil.isNullOrEmptyWithTrim(dataFormat))
			return number.toString();

		DecimalFormat format = new DecimalFormat(dataFormat);
		if (number instanceof Double) {
			if (Double.isNaN(((Double) number).doubleValue())) {
				number = new Double("0.00");
			}

			return format.format(number);
		} else if (number instanceof Float) {
			if (Float.isNaN(((Float) number).floatValue())) {
				number = new Float("0.00");
			}

			return format.format(number);
		} else if (number instanceof Long) {
			if (((Long) number).equals(Long.MIN_VALUE)) {
				number = "";
			}
			return format.format(number);
		} else if (number instanceof Integer) {
			if (((Integer) number).equals(Integer.MIN_VALUE)) {
				number = "";
			}
			return format.format(number);
		} else if (number instanceof BigDecimal) {

			return format.format(number);
		} else
			return number.toString();

	}

	@SuppressWarnings("rawtypes")
	public static String getClassPath(Class cls) {
		String path = cls.getName();
		int index = path.lastIndexOf(".");
		if (index < 0)
			return path;
		else
			return path.substring(0, index);

	}

	/**
	 * 
	 * @param clob
	 * @return
	 */
	public static String getClobString(Clob clob) {
		if (clob == null) {
			return null;
		}
		try {
			Reader inStreamDoc = clob.getCharacterStream();

			char[] tempDoc = new char[(int) clob.length()];
			inStreamDoc.read(tempDoc);
			inStreamDoc.close();
			return new String(tempDoc);
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	public static String getString(Object obj) {
		if (obj == null)
			return "";
		else
			return obj.toString();
	}

	public static String getTrimString(String s) {
		if (null != s)
			return s.trim();
		else
			return null;
	}

	public static String html2text(String html) {
		if (isNullOrEmpty(html))
			return html;

		String dst = html;
		dst = replaceAll(dst, "&lt", "<");
		dst = replaceAll(dst, "&gt;", ">");
		dst = replaceAll(dst, " ", "");
		dst = replaceAll(dst, "<br>", "\n");
		dst = replaceAll(dst, "<br/>", "\n");
		dst = replaceAll(dst, "&nbsp;", " ");
		dst = replaceAll(dst, "\t", "&nbsp;&nbsp;&nbsp;&nbsp;");
		return dst;
	}

	public static boolean isEqual(String string1, String string2) {
		if (string1 == string2) {
			return true;
		}
		if (string1 == null || string2 == null) {
			return false;
		} else {
			return string1.equals(string2);
		}
	}

	public static boolean isEqualIgnoreCaseWithTrim(String string1, String string2) {
		if (string1 == string2) {
			return true;
		}
		if (string1 == null || string2 == null) {
			return false;
		} else {
			return string1.trim().equalsIgnoreCase(string2.trim());
		}
	}

	public static boolean isEqualWithTrim(String string1, String string2) {
		if (string1 == string2) {
			return true;
		}
		if (string1 == null || string2 == null) {
			return false;
		} else {
			return string1.trim().equals(string2.trim());
		}
	}

	public static boolean isNotNullAndNotEmpty(String string) {
		return !isNullOrEmpty(string);
	}

	public static boolean isNotNullAndNotEmptyWithTrim(String string) {
		return !isNullOrEmptyWithTrim(string);
	}

	/**
	 * 如果string不为空null则返回string，否则返回otherString
	 * 
	 * @param stirng
	 * @return
	 */
	public static String isNull(String string, String otherString) {
		if (string == null)
			return otherString;
		else
			return string;
	}

	public static boolean isNullOrEmpty(String string) {
		return string == null || string.isEmpty();
	}

	public static boolean isNullOrEmptyWithTrim(String string) {
		return string == null || string.trim().isEmpty();
	}

	/**
	 * @param inputMessage
	 * @return
	 */
	public static boolean isNumericString(String inputMessage) {
		if (isNullOrEmpty(inputMessage)) {
			return false;
		}
		return Pattern.matches("[\\d]+[.]?[\\d]+", inputMessage);
	}

	/**
	 * 获取字符串的长度，中文占2个字符,英文数字占1个字符
	 * 
	 * @param string
	 *            指定的字符串
	 * @return 字符串的长度
	 */
	public static int length(String string) {
		int valueLength = 0;
		String chinese = "[\u4e00-\u9fa5]";
		// 获取字段值的长度，如果含中文字符，则每个中文字符长度为2，否则为1
		for (int i = 0; i < string.length(); i++) {
			// 获取一个字符
			String temp = string.substring(i, i + 1);
			// 判断是否为中文字符
			if (temp.matches(chinese)) {
				// 中文字符长度为2
				valueLength += 2;
			} else {
				// 其他字符长度为1
				valueLength += 1;
			}
		}

		return valueLength;
	}

	public static String mergeCodeName(String code, String name) {
		StringBuilder sb = new StringBuilder();
		sb.append("[");
		sb.append(code);
		sb.append("]");
		sb.append(name);
		return sb.toString();
	}

	/**
	 * <PRE>
	 * 全角字符->半角字符转换 
	 * 只处理全角的空格，全角！到全角～之间的字符，忽略其他
	 * </PRE>
	 */
	public static String qj2bj(String src) {
		if (src == null) {
			return src;
		}
		StringBuilder buf = new StringBuilder(src.length());
		char[] ca = src.toCharArray();
		for (int i = 0; i < src.length(); i++) {
			if (ca[i] >= SBC_CHAR_START && ca[i] <= SBC_CHAR_END) { // 如果位于全角！到全角～区间内
				buf.append((char) (ca[i] - CONVERT_STEP));
			} else if (ca[i] == SBC_SPACE) { // 如果是全角空格
				buf.append(DBC_SPACE);
			} else { // 不处理全角空格，全角！到全角～区间外的字符
				buf.append(ca[i]);
			}
		}
		return buf.toString();
	}

	/**
	 * Replaces every old substring with a new substring in the big string.
	 * 
	 * @param text
	 *            The big string.
	 * @param oldValue
	 *            The old substring.
	 * @param newValue
	 *            The new substring.
	 * @return The big string with all old substrings replaced with the new
	 *         substring.
	 */
	public static String replaceAll(String text, String oldValue, String newValue) {
		StringBuffer sb = new StringBuffer(text);
		int index = -1;
		while ((index = sb.indexOf(oldValue)) != -1) {
			sb.replace(index, index + oldValue.length(), newValue);
		}
		return sb.toString();
	}

	/**
	 * <PRE>
	 * 提供对字符串的全角->半角，半角->全角转换
	 * </PRE>
	 */

	public static byte[] stringToBytes(String string) {

		return stringToBytes(string, "UTF-8");

	}

	public static byte[] stringToBytes(String string, String charset) {
		try {
			return string.getBytes(charset);
		} catch (UnsupportedEncodingException e) {
			return null;
		}
	}

	public static String text2html(String text) {
		if (isNullOrEmpty(text))
			return text;
		String dst = text;
		dst = replaceAll(dst, "<", "&lt");
		dst = replaceAll(dst, ">", "&gt;");
		dst = replaceAll(dst, "\r\n", "<br>");
		dst = replaceAll(dst, "\r", "<br>");
		dst = replaceAll(dst, "\n", "<br>");
		dst = replaceAll(dst, " ", "&nbsp;");
		dst = replaceAll(dst, "\t", "&nbsp;&nbsp;&nbsp;&nbsp;");

		return dst;
	}

	/**
	 * 
	 * @param error
	 * @return
	 */
	public static String throwableToString(Throwable error) {
		if (null == error)
			return null;

		StringBuffer sb = new StringBuffer();
		sb.append("\nErrorMessage: ");
		sb.append(error.getMessage() == null ? error : error.getMessage());
		sb.append("\nCause: ");
		sb.append(error.getCause());
		sb.append("\nStackTrace:");
		StackTraceElement[] steList = error.getStackTrace();
		if (null != steList) {
			for (StackTraceElement ste : steList) {
				sb.append(ste.toString());
				sb.append("\n");
			}
		}

		return sb.toString();
	}

	/**
	 * Convert one string into an array of strings with line feed as the
	 * delimiter. This method works for text of both Windows and UNIX format.
	 * 
	 * @param text
	 *            The original string.
	 * @return The array of strings splitted from the original text.
	 */
	public static String[] toLineArray(String text) {
		if (text == null || text.trim().length() == 0) {
			return new String[] {};
		}

		ArrayList<String> list = new ArrayList<>();
		char LF = '\n';
		char CR = '\r';
		String line = null;
		for (int fromIndex = 0, toIndex = 0; toIndex != -1 && fromIndex < text.length(); fromIndex = toIndex + 1) {
			toIndex = text.indexOf(LF, fromIndex);
			if (toIndex != -1) {
				if (toIndex > 0 && text.charAt(toIndex - 1) == CR) {
					line = text.substring(fromIndex, toIndex - 1);
				} else {
					line = text.substring(fromIndex, toIndex);
				}
			} else {
				line = text.substring(fromIndex);
			}
			list.add(line);
		}
		return (String[]) list.toArray(new String[] {});
	}

	/**
	 * Convert one string into an array of strings with delimiter specified.
	 * 
	 * @param text
	 *            The original string.
	 * @param delimiter
	 *            The delimiter string.
	 * @return The array of strings splitted from the original text.
	 */
	public static String[] toLineArray(String text, String delimiter) {
		ArrayList<String> list = new ArrayList<>();
		String line = null;
		for (int fromIndex = 0, toIndex = 0; toIndex != -1
				&& fromIndex < text.length(); fromIndex = toIndex + delimiter.length()) {
			toIndex = text.indexOf(delimiter, fromIndex);
			if (toIndex != -1) {
				line = text.substring(fromIndex, toIndex);
				list.add(line);
			}
		}
		return (String[]) list.toArray(new String[] {});
	}

	/**
	 * 将字符串转换成List<String>，支持分号、逗号和空格分隔符
	 * 
	 * @param string
	 * @return
	 */
	public static List<String> toList(String string) {
		if (StringUtil.isNullOrEmptyWithTrim(string))
			return new ArrayList<String>(0);
		string = string.replaceAll(";", " ").replaceAll(",", " ").trim();
		String[] stringArray = string.split(" ");
		List<String> list = new ArrayList<String>(stringArray.length);
		for (String s : stringArray) {
			if (StringUtil.isNotNullAndNotEmptyWithTrim(s))
				list.add(s);
		}
		return list;

	}

	/**
	 * 将字符串转换成List<String>
	 * 
	 * @param string
	 * @return
	 */
	public static List<String> toList(String string, String splitSymbol) {
		if (StringUtil.isNullOrEmptyWithTrim(string))
			return new ArrayList<String>(0);

		String[] stringArray = string.trim().split(splitSymbol);
		List<String> list = new ArrayList<String>(stringArray.length);
		for (String s : stringArray) {
			if (StringUtil.isNotNullAndNotEmptyWithTrim(s))
				list.add(s);
		}
		return list;

	}

	public static String[] toArray(String string) {
		if (StringUtil.isNullOrEmptyWithTrim(string))
			return new String[0];

		List<String> list = toList(string);

		return list.toArray(new String[list.size()]);

	}

	public static String toLowerCase(String s) {
		if (isNotNullAndNotEmpty(s))
			return s.toLowerCase();
		else
			return s;
	}

	public static String toString(Collection<Object> list) {

		if (list != null) {
			List<String> stringList = new ArrayList<String>(list.size());
			for (Object obj : list) {
				stringList.add(obj.toString());
			}
			return toString(stringList.toArray(new String[stringList.size()]));
		} else
			return null;
	}

	public static String toString(Collection<Object> list, String splitSymbol) {

		if (list != null) {
			List<String> stringList = new ArrayList<String>(list.size());
			for (Object obj : list) {
				stringList.add(obj.toString());
			}
			return toString(stringList.toArray(new String[stringList.size()]), splitSymbol);
		} else
			return null;
	}

	public static String toString(String[] array) {
		return toString(array, DEFAULT_SPLIT_SYBMBOL);

	}

	public static String toString(String[] array, String splitSymbol) {
		StringBuffer sb = new StringBuffer();
		if (array != null) {
			for (String s : array) {
				if (sb.length() > 0)
					sb.append(splitSymbol);
				sb.append(s);
			}
			return sb.toString();
		} else
			return null;
	}

	public static String toUpperCase(String s) {
		if (isNotNullAndNotEmpty(s))
			return s.toUpperCase();
		else
			return s;
	}

	public static String trim(String s) {
		if (isNullOrEmpty(s))
			return s;
		else
			return s.trim();
	}

	public static String trimLeft(String s) {
		if (isNullOrEmpty(s))
			return s;
		else {
			while (s.indexOf(" ") == 0 && s.length() > 1) {
				s = s.substring(1);
			}
			if (s.indexOf(" ") == 0)
				return "";
			else
				return s;
		}
	}

	public static String trimRight(String s) {
		if (isNullOrEmpty(s))
			return s;
		else {
			while (s.lastIndexOf(" ") == (s.length() - 1) && s.length() > 1) {
				s = s.substring(0, s.length() - 1);
			}

			if (s.lastIndexOf(" ") == 0)
				return "";
			else
				return s;
		}
	}

	private StringUtil() {

	}
}